#include "cheetah/graphics/texture_gl.h"
#include "cheetah/graphics/utils.h"

namespace cheetah {
namespace graphics {

bool CubeTexture::Initialize(int w, int h, int i_format) const {
  this->Bind();
  for (int i = 0; i < 6; ++i) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, i_format, 
                 w, h, 0, 0, 0, NULL);
  }
  return !CheckErrorsGL("CubeTextue::Initialize");
}
bool CubeTexture::Initialize(const CubeImage &image, int i_format) const {
  this->Bind();
  for (int i = 0; i < 6; ++i) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, i_format, 
                 image.width(), image.height(), 0, image.format(),
                 image.type(), image.data(i));
  }
  return !CheckErrorsGL("CubeTextue::Initialize");
}

bool CubeTexture::Initialize(const Image *images[6], int i_format) const {
  this->Bind();
  for (int i = 0; i < 6; ++i) {
    glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, i_format, 
                 images[i]->width(), images[i]->height(), 0, 
                 images[i]->format(), images[i]->type(), images[i]->data());
  }
  return !CheckErrorsGL("CubeTextue::Initialize");
}

bool Texture2D::Initialize(int w, int h, int i_format) const {
  int type = GL_FLOAT;
  int format = GL_RGBA;
  if (GL_RGBA32UI == i_format || GL_RGBA8UI == i_format || 
      GL_RG8UI == i_format || GL_R8UI == i_format || GL_R8I == i_format) {
    type = GL_UNSIGNED_INT;
    format = GL_RGBA_INTEGER;
  }
  this->Bind();
  glTexImage2D(this->target(), 0, i_format, w, h, 0, format, type, NULL);
  return !CheckErrorsGL("Texture2D::Initialize");
}

bool Texture2D::InitializeDepth(int w, int h, int i_format) const {
  int type = GL_FLOAT;
  int format = GL_DEPTH_COMPONENT;
  if (GL_DEPTH_COMPONENT == i_format) {
    type = GL_UNSIGNED_BYTE;
  }
  this->Bind();
  glTexImage2D(this->target(), 0, i_format, w, h, 0, format, type, NULL);
  return !CheckErrorsGL("Texture2D::InitializeDepth");
}

bool Texture2D::Initialize(const Image &image, int i_format) const {
  this->Bind();  
  glTexImage2D(this->target(), 0, i_format, image.width(), image.height(), 0,
               image.format(), image.type(), image.data());
  return !CheckErrorsGL("Texture2D::Initialize");
}

void Texture2D::Save(const char *filename, int level) const {  
  int w = this->width(), h = this->height();

  float* data = new float[4 * w * h];
  glGetTexImage(this->target(), level, GL_RGBA, GL_FLOAT, data);
  this->Unbind();

  SaveImage(filename, w, h, 1, 4, GL_RGBA, GL_FLOAT, data);
  delete[] data;
}

bool Texture2DArray::Initialize(int w, int h, int z, int i_format) const {
  int type = GL_FLOAT;
  int format = GL_RGBA;

  this->Bind();
  glTexImage3D(this->target(), 0, i_format, w, h, z, 0, format, type, NULL);
  return !CheckErrorsGL("Texture2D::Initialize");
}

void Texture2DArray::Save(const char *filename, int z, int level) const {
  int w, h;
  this->Bind();
  glGetTexLevelParameteriv(this->target(), level, GL_TEXTURE_WIDTH, &w);
  glGetTexLevelParameteriv(this->target(), level, GL_TEXTURE_WIDTH, &h);
}

} // graphics
} // cheetah
